package ch.ethz.fcl.metrobuzz.data.roadnetwork.hierarchy;

import java.util.ArrayList;

import javax.vecmath.Vector2d;

import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.scene.MBScene;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Node;

public class Stroke {
	private int id;
	ArrayList<Arc> arcs;
	final float dangling_thre = 0f; // 80 degree
	float length = 0;

	Node mid = null;
	boolean dangling = false;
	Direction direction;

	public static boolean NORTH = true;
	public static boolean SOUTH = true;
	public static boolean WEST = true;
	public static boolean EAST = true;
	public static boolean DANGLING = true;

	public Stroke(int id) {
		this.id = id;
		arcs = new ArrayList<Arc>();
	}

	public void addArc(Arc arc, int index) {
		arcs.add(index, arc);
	}

	public ArrayList<Arc> getArcs() {
		return arcs;
	}

	public int getId() {
		return id;
	}

	/**
	 * calculate all attributes for this stroke
	 */

	public void init(MBScene scene) {
		// length
		for (int i = 0; i < arcs.size(); i++)
			length += arcs.get(i).getLength();

		float temp_length = 0;
		int index = 0;
		Edge edge = null;
		while (temp_length < length / 2 && index < arcs.size() - 1) {
			for (int i = 0; i < arcs.get(index).size(); i++) {
				edge = arcs.get(index).getEdges().get(i);
				temp_length += edge.length();
				if (temp_length >= length / 2)
					break;
			}
			index++;
		}
		if (edge != null) {
			Node temp_start = scene.getNode(edge.getStartNodeIndex());
			Node temp_end = scene.getNode(edge.getEndNodeIndex());
			mid = new Node(temp_start.getId() + "_" + temp_end.getId(),
					(temp_start.getX() + temp_end.getX()) / 2,
					(temp_start.getY() + temp_end.getY()) / 2);
		} else
			mid = getStartNode(scene);

		// dangling
		Node start = getStartNode(scene);
		Node end = getEndNode(scene);

		Vector2d v1 = new Vector2d(mid.getX() - start.getX(), mid.getY()
				- start.getY());
		Vector2d v2 = new Vector2d(end.getX() - mid.getX(), end.getY()
				- mid.getY());

		float result = (float) (v1.dot(v2) / (v1.length() * v2.length()));

		if (result > dangling_thre)
			dangling = false;
		else
			dangling = true;

		// direction
		float y_diff = end.getY() - start.getY();
		float x_diff = end.getX() - start.getX();

		if (x_diff == 0)
			if (y_diff > 0)
				direction = Direction.North;
			else
				direction = Direction.South;
		else if (x_diff > 0 && y_diff >= 0)
			if (y_diff / x_diff < 1)
				direction = Direction.East;
			else
				direction = Direction.North;

		else if (x_diff < 0 && y_diff >= 0)
			if (y_diff / x_diff < -1)
				direction = Direction.North;
			else
				direction = Direction.West;
		else if (x_diff < 0 && y_diff <= 0)
			if (y_diff / x_diff > 1)
				direction = Direction.South;
			else
				direction = Direction.West;
		else if (x_diff > 0 && y_diff <= 0)
			if (y_diff / x_diff < -1)
				direction = Direction.South;
			else
				direction = Direction.East;
	}

	public Node getStartNode(MBScene scene) {
		Edge start = arcs.get(0).getStartEdge();
		return scene.getNode(start.getStartNodeIndex());
	}

	public Node getEndNode(MBScene scene) {
		Edge end = arcs.get(size() - 1).getEndEdge();
		return scene.getNode(end.getEndNodeIndex());
	}

	public int size() {
		return arcs.size();
	}

	public float getLength() {
		return length;
	}

	Node getMidNode() {
		return mid;
	}

	public boolean isDangling() {
		return dangling;
	}

	public float getAverageDensity(float start, float end) {
		float sum = 0;
		int size = 0;

		for (Arc arc : arcs)
			for (Edge edge : arc.getEdges()) {
				sum += edge.getPassTripIds(start, end).size();
				size++;
			}
		return sum / size;
	}

	public void render(MBScene scene, int max_edge_weight,
			float edges_render_level) {
		GL11.glColor4b((byte) 40, (byte) 55, (byte) 30, (byte) 100);

		float r = (float) Math.log(getAverageDensity(MBData.startTime
				/ (float) MBData.ONE_DAY_TIME,
				(MBData.startTime + MBData.period)
						/ (float) MBData.ONE_DAY_TIME)
				/ Math.log(max_edge_weight));

		if (r > edges_render_level) {
			// rend all strokes
			for (Arc arc : this.getArcs()) {
				ArrayList<Edge> edges = arc.getEdges();
				for (int j = 0; j < edges.size(); j++) {
					float x = (float) edges
							.get(j)
							.getPassTripIds(
									MBData.startTime
											/ (float) MBData.ONE_DAY_TIME,
									(MBData.startTime + MBData.period)
											/ (float) MBData.ONE_DAY_TIME)
							.size()
							/ max_edge_weight;
					if (x < 0.1f)
						GL11.glLineWidth(1.0f);
					else if (x > 1.0f)
						GL11.glLineWidth(20);
					else
						GL11.glLineWidth(20 * x);
					GL11.glBegin(GL11.GL_LINES);
					edges.get(j).render();
					GL11.glEnd();
				}
			}
		}

	}

	enum Direction {
		West, East, North, South
	}
}
